package com.ken.common.redis.aop;

import com.ken.common.core.utils.SpelExpressionUtils;
import com.ken.common.redis.annotation.CLock;
import com.ken.common.redis.lock.LockUtils;
import com.ken.common.redis.mode.LockMode;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.util.StringUtils;

import java.lang.reflect.Method;

/**
 * order设置优先级 越小优先级越高 为了在事务提交之后 再释放分布式锁
 */
@Aspect
@Order(1)
public class RLockAop {

    @Autowired(required = false)
    private DataSourceTransactionManager transactionManager;

    /**
     * 分布式锁Aop
     * @return
     */
    @Around("@annotation(com.ken.common.redis.annotation.CLock)")
    public Object rLockAop(ProceedingJoinPoint joinPoint) throws Throwable {

        //获得方法上的注解
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        CLock cLock = method.getAnnotation(CLock.class);

        //解析分布式锁的key值
        String key = SpelExpressionUtils.parserSpel(method, joinPoint.getArgs(), cLock.key(), String.class, null);

        //分布式锁对象
        try {
            //判断是否为自动加锁模式
            if (cLock.lockMode() == LockMode.AUTO && !StringUtils.isEmpty(key)) {
                //设置分布式锁
                LockUtils.lockSync(key);
            }

            Object result = joinPoint.proceed();
            return result;
        } catch (Throwable e) {
            throw e;
        } finally {
            //解除分布式锁
            LockUtils.unlock();
        }
    }
}
